# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET;
from xml.etree.ElementTree import Element, SubElement, ElementTree;
import math

# 尺寸
class Size(object):
    def __init__(self):
        self.height = 0;
        self.width = 0;
        self.radius = 0;


# 空间
class Area(object):
    def __init__(self):
        self.index = 0;
        self.location = [];


# 库 包含各种方法
class PipeGroup(object):
    def __init__(self):
        self.pipeGroupNo = 0;
        self.type = "";
        self._teeList = []
        self._pipeLists = [];
        self.connectors = []

    def getTeeType(self):
        doubleTeeList, singleTeeList, zeroTeeList = [], [], []
        for tee in self._teeList:
            if tee.type == 'double':
                doubleTeeList.append(tee)
            elif tee.type == 'single':
                singleTeeList.append(tee)
            elif tee.type == 'zero':
                zeroTeeList.append(tee)
        return doubleTeeList, singleTeeList, zeroTeeList

# 组
class PipeList(object):
    def __init__(self):
        self.pipeListNo = 0;
        self.prevListNo = 0;
        self.teeId_Next = "";
        self.pipeListInfo = []
        # self.teePoint_Next=[];

        # 不关键的属性
        self.systemType = ""
        self.ductType = ""
        self.familyName = ""
        self.symbolName = ""
        self.systemClassfy = ""
        self.insulationTypeName = ""
        self.insulationThickness = ""
        self.horizonOffset = ""
        self.verticalOffset = ""
        self.color = ""
        self.mark = ""

        # self.SDR="";
        self._nodes = []
        self._pipes = []


# 列
class Pipe(object):
    def __init__(self):
        self.uid = "";
        self.start = [];
        self.end = [];
        self.width = 0;
        self.height = 0;
        self.pipeInfo = []
        self.transform = ""
        self.type = "";
        self.shape = "";
        self.angle = 0

        self.size = Size();
        self.area = Area();

        # todo cmf 2023-12-7修改：添加管道是否避障成功的属性 0默认 1避障成功 2避障失败
        self.if_successful_avoid = "没有避障"
        # cmf end

# 管道
class Tee:
    def __init__(self):
        self.position = []  # 三通位置
        self.group = []  # 三通属于第几组管道
        self.lists = []  # 三通连接管道列的标号
        self.connectorEntitys = []  # 三通连接的管道段的uid
        self.uid = 0  # 三通的id
        self.type = ''  # 三通的类型
        self.familyName = ""
        self.symbolName = ""


class PipeBase(object):
    uniqueId = 100000;

    # 初始化传入xml路径,读取到库中
    def __init__(self, xmlPath):
        self.yellowBallCoordinates = []
        self.blueBallCoordinates = []
        self._pipeGroups = [];
        self.currentGroup = 0;
        self.currentList = 0;
        self.readedPath = xmlPath;
        self.isSingleFile = True;

        tree = ET.parse(xmlPath);
        root = tree.getroot();
        pipeBase = root.find("PipeBase")
        teesXml = root.find('Tee')
        if (pipeBase == None):
            self.isSingleFile = False;
            pipeBase = root;

        for pipeGroupXml in pipeBase:
            pipeGroup = PipeGroup();
            pipeGroup.pipeGroupNo = intTryParse(pipeGroupXml.attrib["PipeGroupNo"]);
            pipeGroup.type = pipeGroupXml.attrib["type"];
            for teeXml in teesXml:
                if pipeGroup.pipeGroupNo == intTryParse(teeXml.attrib['Group']):
                    tee = Tee()
                    tee.group = intTryParse(teeXml.attrib["Group"])
                    [tee.lists.append(int(pipelist)) for pipelist in teeXml.attrib['Lists'].split(';')]
                    [tee.connectorEntitys.append(connector) for connector in
                     teeXml.attrib['ConnectorEntitys'].split(';')]
                    tee.uid = teeXml.attrib['UniqueId']
                    tee.type = teeXml.attrib['type']
                    tee.symbolName = teeXml.attrib["SymbolName"]
                    tee.familyName = teeXml.attrib["FamilyName"]
                    pipeGroup._teeList.append(tee)

            self._pipeGroups.append(pipeGroup);

            for pipeListXml in pipeGroupXml:
                pipeList = PipeList();
                pipeList.pipeListNo = intTryParse(pipeListXml.attrib["PipeListNo"]);
                pipeList.prevListNo = intTryParse(pipeListXml.attrib["PrevListNo"]);

                # 超多属性的设置
                pipeList.familyName = pipeListXml.attrib["FamilyName"];
                pipeList.symbolName = pipeListXml.attrib["SymbolName"];
                pipeList.systemClassfy = pipeListXml.attrib["SystemClassfy"];
                pipeList.systemType = pipeListXml.attrib["SystemType"];
                pipeList.insulationTypeName = pipeListXml.attrib["InsulationTypeName"];
                pipeList.insulationThickness = pipeListXml.attrib["InsulationTypeThickness"]
                pipeList.horizonOffset = pipeListXml.attrib["HorizonOffset"];
                pipeList.verticalOffset = pipeListXml.attrib["VerticalOffset"];
                pipeList.color = pipeListXml.attrib["Color"];
                pipeList.mark = pipeListXml.attrib["Mark"];
                if (pipeGroup.type == "Duct"):
                    pipeList.ductType = pipeListXml.attrib["DuctType"];

                pipeGroup._pipeLists.append(pipeList);

                i = 0
                for pipeXml in pipeListXml:
                    if pipeXml.tag == "Pipe":
                        pipe = Pipe();
                        pipe.uid = pipeXml.attrib["UniqueId"];
                        temp = floatTryParse(pipeXml.attrib["Height"]);
                        if (temp == "" or temp == 0):
                            temp = float(pipeXml.attrib["Width"]) * 2;
                            pipe.size.width = temp;
                            pipe.size.height = temp;
                        else:
                            pipe.size.height = temp;
                            temp = float(pipeXml.attrib["Width"])
                            pipe.size.width = temp;

                            if (pipeGroup.type == "Pipe" or pipeGroup.type == "LinePipe"):
                                pipe.size.radius = pipe.size.width / 2;

                        [pipe.start.append(float(temp_str)) for temp_str in pipeXml.attrib["StartPoint"].split(",")]
                        [pipe.end.append(float(temp_str)) for temp_str in pipeXml.attrib["EndPoint"].split(",")]
                        pipe.pipeInfo = [pipe.start, pipe.end, pipe.size.width, pipe.size.height]


                        pipe.transform = pipeXml.attrib["Transform"] #风管Transform不为空，水管为空

                        flag1 = pipeGroup.type == 'LineDuct' or pipeGroup.type == 'Duct'
                        flag2 = pipe.start[0] == pipe.end[0] and pipe.start[1] == pipe.end[1]
                        if flag1 and flag2:
                            tranform = [temp_str for temp_str in pipeXml.attrib["Transform"].split(";")]
                            try:
                                normal_vector = [float(temp_str) for temp_str in tranform[2].split(",")]
                                if normal_vector[1] == 1 or normal_vector[1] == -1:
                                    angle = math.pi / 2
                            except:
                                pass
                            else:
                                try:
                                    tan_value = normal_vector[1] / normal_vector[0]
                                    angle = math.atan(tan_value)
                                    pipe.angle = angle
                                except:
                                    pipe.angle = None

                        else:
                            pipe.angle = None
                        pipeList.pipeListInfo.append(pipe.pipeInfo)
                        pipeList._pipes.append(pipe)
                    elif pipeXml.tag == "Point" and i != 0 and i != len(pipeListXml)-1:
                        node = Node()
                        node.uid = pipeXml.attrib["UniqueId"]
                        node.familyName = pipeXml.attrib["FamilyName"]
                        node.symbolName = pipeXml.attrib["SymbolName"]
                        [node.connectorEntitys.append(entity) for entity in pipeXml.attrib["ConnectorEntitys"].split(";")]
                        pipeList._nodes.append(node)
                    i += 1

    # 输出xml
    def outputXml(self, outPath):
        root = Element('PipeBase');
        teeXml = Element('Tee')
        root_autoConnect = Element('AutoConnect')
        root_clashPoint = Element('ClashPoints')
        for clashPoint in self.yellowBallCoordinates:
            clashPoints = SubElement(root_clashPoint, 'ClashPoint')
            clashPoints.attrib['FamilyName'] = "半透明球（黄色）-20220817"
            clashPoints.attrib['Point'] = ','.join([str(point) for point in clashPoint])
            clashPoints.attrib['半径'] = '300'
        for clashPoint in self.blueBallCoordinates:
            clashPoints = SubElement(root_clashPoint, 'ClashPoint')
            clashPoints.attrib['FamilyName'] = "半透明球（蓝色）-20220817"
            clashPoints.attrib['Point'] = ','.join([str(point) for point in clashPoint])
            clashPoints.attrib['半径'] = '300'
        for pipeGroup in self._pipeGroups:
            pipeGroupXml = SubElement(root, 'PipeGroup');
            for connect_uid in pipeGroup.connectors:
                connects = SubElement(root_autoConnect, 'Connect')
                connects.attrib['Entitys'] = ';'.join([str(uid) for uid in connect_uid[0]])
                connects.attrib['FamilyName'] = connect_uid[-2]
                connects.attrib['SymbolName'] = connect_uid[-1]

            pipeGroupXml.attrib['PipeGroupNo'] = str(pipeGroup.pipeGroupNo);
            pipeGroupXml.attrib['Type'] = str(pipeGroup.type);

            for pipeList in pipeGroup._pipeLists:
                pipeListXml = SubElement(pipeGroupXml, 'PipeList');

                # 超多属性的设置
                pipeListXml.attrib['PipeListNo'] = str(pipeList.pipeListNo);
                pipeListXml.attrib['PrevListNo'] = str(pipeList.prevListNo);
                pipeListXml.attrib['TeeId_Next'] = str(pipeList.teeId_Next);

                pipeListXml.attrib["FamilyName"] = str(pipeList.familyName);
                pipeListXml.attrib["SymbolName"] = str(pipeList.symbolName);
                pipeListXml.attrib["SystemClassfy"] = str(pipeList.systemClassfy);
                pipeListXml.attrib["SystemType"] = str(pipeList.systemType);
                pipeListXml.attrib["InsulationTypeName"] = str(pipeList.insulationTypeName)
                pipeListXml.attrib["InsulationTypeThickness"] = str(pipeList.insulationThickness)
                pipeListXml.attrib["HorizonOffset"] = str(pipeList.horizonOffset);
                pipeListXml.attrib["VerticalOffset"] = str(pipeList.verticalOffset);
                pipeListXml.attrib["Color"] = str(pipeList.color);
                if (pipeGroup.type == "Duct"):
                    pipeListXml.attrib['DuctType'] = str(pipeList.ductType);
                if (pipeGroup.type == "LinePipe" or pipeGroup.type == "LineDuct"):
                    pipeListXml.attrib["Mark"] = str(pipeList.mark);

                for pipe in pipeList._pipes:
                    pipeXml = SubElement(pipeListXml, 'Pipe');
                    pipeXml.attrib['UniqueId'] = str(pipe.uid);
                    pipeXml.attrib['StartPoint'] = ','.join([str(tempFloat) for tempFloat in pipe.start]);
                    pipeXml.attrib['EndPoint'] = ','.join([str(tempFloat) for tempFloat in pipe.end]);
                    pipeXml.attrib['Width'] = str(pipe.size.width);
                    pipeXml.attrib['Height'] = str(pipe.size.height);
                    pipeXml.attrib['Transform'] = str(pipe.transform)
            for tee in pipeGroup._teeList:
                tee_s = SubElement(teeXml, 'Connector')
                tee_s.attrib['Group'] = str(tee.group)
                tee_s.attrib['PipeGroupType'] = pipeGroup.type
                tee_s.attrib['UniqueId'] = str(tee.uid)
                tee_s.attrib['Lists'] = ';'.join([str(i) for i in tee.lists])
                tee_s.attrib['ConnectorEntitys'] = ';'.join([str(i) for i in tee.connectorEntitys])
                tee_s.attrib['FamilyName'] = str(tee. familyName)
                tee_s.attrib['SymbolName'] = str(tee.symbolName)


        if (self.isSingleFile):
            tree = ET.parse(self.readedPath);
            oldroot = tree.getroot();
            oldroot.remove(oldroot.find("PipeBase"));
            oldroot.append(root);

            oldroot.remove(oldroot.find("Tee"));
            oldroot.append(teeXml)

            oldroot.append(root_autoConnect)
            oldroot.append(root_clashPoint)
        else:
            tree = ElementTree(root);
        tree.write(outPath, "UTF-8");

    def sizeOrder(self):
        self._pipeGroups.sort(
            key=lambda elem: elem._pipeLists[0]._pipes[0].size.width + elem._pipeLists[0]._pipes[0].size.height,
            reverse=True)

    def duct_scale_modify(self):
        for i, pipe_group in enumerate(self._pipeGroups):
            if pipe_group.type != "Duct":
                continue
            for j, pipe_list in enumerate(pipe_group._pipeLists):
                for z, pipe in enumerate(pipe_list._pipes):
                    width = pipe.size.width
                    height = pipe.size.height
                    if width / height < 1 / 6:
                        while width / height < 1 / 6:
                            width = width + 50
                            height = round(pipe.size.width * pipe.size.height / width /50) * 50
                    if width / height > 6:
                        while width / height > 6:
                            width = width - 50
                            height = round(pipe.size.width * pipe.size.height / width / 50) * 50
                    self._pipeGroups[i]._pipeLists[j]._pipes[z].size.width = width
                    self._pipeGroups[i]._pipeLists[j]._pipes[z].size.height = height



    def sizeOrder_byDistance(self):
        self._pipeGroups.sort(
            key=lambda elem: distance_to_origin(elem._pipeLists[0]._pipes[0].start),
            reverse=False  # 注意这里是升序
        )
            
    def output_sizeOrder(self):
        self._pipeGroups.sort(
            key=lambda elem: elem.pipeGroupNo,reverse=False);

def distance_to_origin(point):
    return math.sqrt(point[0] ** 2 + point[1] ** 2 + point[2] ** 2)
def intTryParse(value):
    try:
        return int(value)
    except ValueError:
        return value


class Node:
    def __init__(self):
        self.node = ""
        self.familyName = ""
        self.symbolName = ""
        self.connectorEntitys = []


def floatTryParse(value):
    try:
        return float(value)
    except ValueError:
        return value

if __name__ == '__main__':
    pipeBase = PipeBase('C:/Users/N701/Desktop/revit_order4.xml')
    pipeBase.outputXml('C:/Users/N701/Desktop/revit_order.xml')